//
//  IJKPlayer.swift
//  VideoPlayer
//
//  Created by JY_NEW on 2021/10/8.
//

import Foundation

#if canImport(IJKMediaFrameworkWithSSL)

import IJKMediaFrameworkWithSSL

/// IJK播放器适配器
public class IJKPlayerAdapter: IJKFFMoviePlayerController, CorePlayerAdapterType {
    
    public weak var delegate: CorePlayerAdapterDelegate?
    
    /// 播放状态
    public var status: CorePlayerStatus = .stoped(.unload) {
        didSet {
            if oldValue != self.status {
                DispatchQueue.main.async { [weak self] in
                    guard let self = self else { return }
                    self.delegate?.playerAdapter(self, didChangeStatus: self.status)
                }
            }
        }
    }
    
    public var presentationSize: CGSize {
        return self.naturalSize 
    }
    
    public var rate: Float {
        get { return self.playbackRate }
        set { self.playbackRate = newValue }
    }
    
    public var volume: Float {
        get { return self.playbackVolume }
        set { self.playbackVolume = newValue }
    }
    
    public var currentTime: TimeInterval {
        get { return self.currentPlaybackTime }
        set { self.currentPlaybackTime = newValue }
    }
    
    public var isReadyForDisplay: Bool = false {
        didSet {
            DispatchQueue.main.async { [weak self] in
                guard let self = self else { return }
                self.delegate?.playerAdapterReadyForDisplay(self)
            }
        }
    }
    
//    public var videoGravity: AVLayerVideoGravity = .resizeAspect {
//        didSet {
//            switch self.videoGravity {
//            case .resize: self.scalingMode = .fill
//            case .resizeAspect: self.scalingMode = .aspectFit
//            case .resizeAspectFill: self.scalingMode = .aspectFill
//            default: self.scalingMode = .none
//            }
//        }
//    }
    
    /// 准备好后是否自动播放，用于准备好前控制播放
    private var _playWhenPrepared = false
    /// 是否跳转中
    private var _isSeeking: Bool = false
    /// 跳转时间
    private var _seekingTime: TimeInterval = 0
    /// 跳转时间结束操作
    private var _seekCompletion: ((Bool) -> Void)?
    
    public override init!(contentURL aUrl: URL!, with options: IJKFFOptions!) {
        super.init(contentURL: aUrl, with: options)
//        self.initialize()
    }
    public override init!(contentURLString aUrlString: String!, with options: IJKFFOptions!) {
        super.init(contentURLString: aUrlString, with: options)
        self.initialize()
    }
    public override init!(moreContent aUrl: URL!, with options: IJKFFOptions!, withGLView glView: (UIView & IJKSDLGLViewProtocol)!) {
        super.init(moreContent: aUrl, with: options, withGLView: glView)
//        self.initialize()
    }
    public override init!(moreContentString aUrlString: String!, with options: IJKFFOptions!, withGLView glView: (UIView & IJKSDLGLViewProtocol)!) {
        super.init(moreContentString: aUrlString, with: options, withGLView: glView)
        self.initialize()
    }
    private func initialize() {
        NotificationCenter.default.addObserver(self, selector: #selector(self._preparedToPlayDidChange(_:)), name: .IJKMPMediaPlaybackIsPreparedToPlayDidChange, object: self)
        
        NotificationCenter.default.addObserver(self, selector: #selector(self._playbackDidFinish(_:)), name: .IJKMPMoviePlayerPlaybackDidFinish, object: self)
        NotificationCenter.default.addObserver(self, selector: #selector(self._playbackStateDidChange(_:)), name: .IJKMPMoviePlayerPlaybackStateDidChange, object: self)
        NotificationCenter.default.addObserver(self, selector: #selector(self._loadStateDidChange(_:)), name: .IJKMPMoviePlayerLoadStateDidChange, object: self)
        NotificationCenter.default.addObserver(self, selector: #selector(self._naturalSizeAvailable(_:)), name: .IJKMPMovieNaturalSizeAvailable, object: self)
        
        NotificationCenter.default.addObserver(self, selector: #selector(self._didSeekComplete(_:)), name: .IJKMPMoviePlayerDidSeekComplete, object: self)
        NotificationCenter.default.addObserver(self, selector: #selector(self._seekRenderingStart(_:)), name: .IJKMPMoviePlayerSeekAudioStart, object: self)
        NotificationCenter.default.addObserver(self, selector: #selector(self._seekRenderingStart(_:)), name: .IJKMPMoviePlayerSeekVideoStart, object: self)
        
        NotificationCenter.default.addObserver(self, selector: #selector(self._firstVideoFrameRendered(_:)), name: .IJKMPMoviePlayerFirstVideoFrameRendered, object: self)
        
        NotificationCenter.default.addObserver(self, selector: #selector(self._audioSessionInterruption(_:)), name: AVAudioSession.interruptionNotification, object: self)
        NotificationCenter.default.addObserver(self, selector: #selector(self._audioSessionRouteChange(_:)), name: AVAudioSession.routeChangeNotification, object: self)
        NotificationCenter.default.addObserver(self, selector: #selector(self._willEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: self)
        self.setPauseInBackground(false)
        self.shouldAutoplay = false
        self.status = .stoped(.preparing)
        self.prepareToPlay()
    }
    deinit {
        NotificationCenter.default.removeObserver(self)
//        super.stop()
//        super.shutdown()
//        self.view.removeFromSuperview()
    }
    
    public override func play() {
        if self.isPreparedToPlay {
            if self.status.isFinished && !self._isSeeking {
                self.seek(to: .zero, completion: nil)
            }else{
                super.play()
            }
        }else{
            self._playWhenPrepared = true
            self.status = .playing(.preparing)
        }
    }
    public override func pause() {
        if self.isPreparedToPlay {
            super.pause()
        }else{
            self._playWhenPrepared = false
            self.status = .paused
        }
    }
    public override func stop() {
        self.status = .stoped(.exited)
        super.stop()
        self.shutdown()
    }
    
    public func seek(to time: TimeInterval, completion: ((Bool) -> Void)?) {
        self._willSeeking(to: time, completion: completion)
        var secs = time
        if ceil(secs) == ceil(self.duration) {
            secs *= 0.98
        }
        if secs == 0 {
            secs = 0.001
        }
        self.currentPlaybackTime = secs
        self.play()
    }
    private func _willSeeking(to time: TimeInterval, completion: ((Bool) -> Void)?) {
        if self._isSeeking {
            // 重新定位则上一次未完成的定位失败
            self._seekCompletion?(false)
        }
        self._isSeeking = true
        self._seekingTime = time
        self._seekCompletion = completion
        self._updateStatus()
    }
    private func _didEndSeeking(_ finished: Bool) {
        if self._isSeeking {
            self._isSeeking = false
            self._seekCompletion?(true)
            self._seekCompletion = nil
            self._updateStatus()
        }
    }
    /// 判断自身的状态并做相应的处理
    private func _updateStatus() {
        switch self.playbackState {
        case .stopped:
            if !self.isPreparedToPlay {
                self.status = .stoped(.preparing)
            }else if !self.status.isStoped {
                self.status = .stoped(.error)
            }
        case .paused:
            if self._isSeeking {
                self.status = .playing(.seeking)
            }else
            if self._playWhenPrepared {
                self.status = .playing(.preparing)
            }else{
                self.status = .paused
            }
        case .playing, .interrupted, .seekingForward, .seekingBackward:
            if !self.isPreparedToPlay {
                self.status = .playing(.preparing)
            }else if self._isSeeking {
                self.status = .playing(.seeking)
            }else if self.loadState.contains(.stalled) {
                self.status = .playing(.stalled)
            }else{
                self.status = .playing(.good)
            }
        @unknown default:
            break
        }
    }
    
    // MARK: 消息通知
    
    @objc func _preparedToPlayDidChange(_ note: NSNotification) {
        self._updateStatus()
        DispatchQueue.main.async { [weak self] in
            guard let self = self else { return }
            self.delegate?.playerAdapter(self, didChangeDuration: self.duration)
            self.delegate?.playerAdapter(self, didChangePlayableDuration: self.playableDuration)
            if self.isPreparedToPlay {
                if self._playWhenPrepared {
                    self._playWhenPrepared = false
                    if self._isSeeking {
                        self.currentPlaybackTime = self._seekingTime
                    }
                    self.play()
                }else{
                    if self._isSeeking {
                        self.currentPlaybackTime = self._seekingTime
                        self._didEndSeeking(false)
                        self._updateStatus()
                    }
                }
            }
        }
    }
    @objc func _playbackDidFinish(_ note: NSNotification) {
        if let reason = note.userInfo?[IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey] as? Int, let ijkReason = IJKMPMovieFinishReason(rawValue: reason) {
            switch ijkReason {
            case .playbackEnded:
                self.status = .stoped(.finished)
            case .playbackError:
                self.status = .stoped(.error)
            case .userExited:
                self.status = .stoped(.exited)
            default:
                self.status = .stoped(.error)
            }
        }else{
            self.status = .stoped(.error)
        }
    }
    @objc func _playbackStateDidChange(_ note: NSNotification) {
        self._updateStatus()
    }
    @objc func _loadStateDidChange(_ note: NSNotification) {
        self._updateStatus()
    }
    @objc func _naturalSizeAvailable(_ note: NSNotification) {
        DispatchQueue.main.async { [weak self] in
            guard let self = self else { return }
            self.delegate?.playerAdapter(self, didChangePresentationSize: self.presentationSize)
        }
    }
    @objc func _didSeekComplete(_ note: NSNotification) {
        if let isError = note.userInfo?[IJKMPMoviePlayerDidSeekCompleteErrorKey] as? Bool, isError {
            DispatchQueue.main.async {
                self._didEndSeeking(false)
            }
        }
    }
    @objc func _seekRenderingStart(_ note: NSNotification) {
        DispatchQueue.main.async {
            self._didEndSeeking(true)
        }
    }
    @objc func _firstVideoFrameRendered(_ note: NSNotification) {
        self.isReadyForDisplay = true
    }
    @objc func _audioSessionInterruption(_ note: NSNotification) {
        if let type = note.userInfo?[AVAudioSessionInterruptionTypeKey] as? Int,
           type == AVAudioSession.InterruptionType.began.rawValue {
            self.pause()
        }
    }
    @objc func _audioSessionRouteChange(_ note: NSNotification) {
        DispatchQueue.main.async {
            if let reason = note.userInfo?[AVAudioSessionRouteChangeReasonKey] as? Int,
               reason == AVAudioSession.RouteChangeReason.oldDeviceUnavailable.rawValue {
                self.pause()
            }
        }
    }
    @objc func _willEnterForeground(_ note: NSNotification) {
        if self.status.isPaused {
            self.pause()
        }else{
            self.play()
        }
    }
}
#endif
